/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cs575.coresystem;

import cs575.dbentities.Converter;
import cs575.dbentities.GroupEx;
import cs575.dbentities.GroupInvitation;
import cs575.dbentities.GroupInvitationPK;
import cs575.dbentities.GroupMember;
import cs575.dbentities.GroupMemberPK;
import cs575.dbentities.IGroup;
import cs575.dbentities.IGroupInvitation;
import cs575.dbentities.IGroupRole;
import cs575.dbentities.Role;
import cs575.dbentities.User;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

/**
 *
 * @author bms
 */
public class Facade {

    private EntityManagerFactory entityManagerFactory;
    private EntityManager entityManager;
    private Accounting logger = new Accounting();
    private Authentication auth = new Authentication();
    private Authorization authoriz = new Authorization();
    private GroupManager group;
    private UserManager user;
    private TaskManagerE task;
    private Session session;

    public Facade() {
        entityManagerFactory = Persistence.createEntityManagerFactory("TasksManagementPU");
        entityManager = entityManagerFactory.createEntityManager();
    }

    // <editor-fold defaultstate="collapsed" desc="basic services-methods">
    public Session login(String username, String password) {
        session = auth.authenticate(username, password);
        return session;
    }

    public void logout(Session currentSession) {
        auth.endSession(currentSession);
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="user-methods">
    public boolean createUser(String userName, String email, String password) {
        return _createUser(userName, email, password);
    }

    public boolean editUser(Session session, int id, String userName, String email, String password) {
        boolean result = false;
        if (validateAuth(session)) {
            if (session.getUserID() == id) // authorization users only allowed to change their own information 
            {
                result = _editUser(id, userName, email, password);
            }
        }
        return result;
    }

    public boolean removeUser(int id) {
        return _removeUser(id);
    }

    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="group-methods">
    public boolean createGroup(Session session, String groupName, String groupDescription) {
        boolean result = false;
        if (validateAuth(session)) {
            {
                result = _createGroup(groupName, groupDescription);
            }
        }
        return result;
    }

    public boolean editGroup(Session session, int id, String groupName, String groupDescription) {
        boolean result = false;
        if (validateAuth(session)) {
            // authorization Admins only allowed to edit their groups
            if (authoriz.isAuthorized(new GroupEx(id), Authorization.G_edit_group)) {
                result = _editGroup(id, groupName, groupDescription);
            }
        }
        return result;

    }

    public boolean inviteUserToGroup(Session session, int groupId, int destUser, String comment) {
        boolean result = false;
        if (validateAuth(session)) {
            // authorization Admins only allowed to invite users to a group
            if (authoriz.isAuthorized(new GroupEx(groupId), Authorization.G_invite_user)) {
                result = _inviteUserToGroup(groupId, destUser, comment);
            }
        }
        return result;
    }

    public IGroup getGroupInfo(Session session, int groupId) {
        if (validateAuth(session)) {
            // TODO: authorization Admins only allowed to invite users to a group
            if (authoriz.isAuthorized(new GroupEx(groupId), Authorization.G_read_Group)) {
                return _getGroupInfo(groupId);
            }
        }
        return null;
    }

    public IGroupRole[] getGroups(Session session, int sourceUser) {
        if (validateAuth(session)) {
            // TODO: authorization Admins only allowed to invite users to a group
            if (session.getUserID() == sourceUser) {
                return _getGroups(sourceUser);
            }
        }
        return null;
    }

    public IGroupRole[] getGroupMembers(Session session, int groupId) {
        if (validateAuth(session)) {
            // TODO: authorization Admins only allowed to invite users to a group
            if (authoriz.isAuthorized(new GroupEx(groupId), Authorization.G_read_Group)) {
                return _getGroupMembers(groupId);
            }
        }
        return null;
    }

    public void acceptGroupInvitation(Session session, int groupId, int userId) {
        if (validateAuth(session)) {
        if (session.getUserID() == userId){
                _acceptGroupInvitation(groupId, userId);
            }
        }
    }

    public void rejectGroupInvitation(Session session, int groupId, int userId) {
        if (validateAuth(session)) {
            if (session.getUserID() == userId) 
            {
                _rejectGroupInvitation(groupId, userId);
            }
        }
    }

    public IGroupInvitation[] getGroupsInvitation(Session session, int userId) {
        if (validateAuth(session)) {
            if (session.getUserID() == userId) 
            {
                return _getGroupsInvitation(userId);
            }
        }
        return null;
    }

    // </editor-fold>
    private boolean validateAuth(Session session) {
        this.session = auth.authenticate(session);
        return (this.session != null);
    }

    private boolean _createUser(String userName, String email, String password) {
        boolean result = false;
        EntityTransaction trans = entityManager.getTransaction();
        trans.begin();
        User paramUser = user.createUser(userName, email, password);
        if (paramUser != null) {
            if (user.storeUser(paramUser)) {
                result = true;
            }
        }

        if (result) {
            trans.commit();
        } else {
            trans.rollback();
        }
        return result;
    }

    private boolean _editUser(int id, String userName, String email, String password) {
        return user.editUser(new User(id, userName, password, email));
    }

    private boolean _removeUser(int id) {
        // this method is not supported right now 
        return false;
    }

    private boolean _createGroup(String groupName, String groupDescription) {
        GroupEx param = group.createGroup(groupName, groupDescription, user.createUserReference(session.getUserID()));
        if (param != null) {
            return true;
        } else {
            return false;
        }
    }

    private boolean _editGroup(int groupId, String groupName, String groupDescription) {
        return group.editGroup(new GroupEx(groupId, groupName, groupDescription));
    }

    private boolean _inviteUserToGroup(int groupId, int destUser, String comment) {
        return group.inviteUser(new GroupEx(groupId), new User(session.getUserID()), new User(destUser), comment);

    }

    void _acceptGroupInvitation(int groupId, int retrieveUser) {
        group.acceptInvitation(group.createGroupReference(groupId), user.createUserReference(retrieveUser));
    }

    void _rejectGroupInvitation(int GroupEx, int retrieveUser) {
        group.rejectInvitation(group.createGroupReference(GroupEx), user.createUserReference(retrieveUser));
    }

    IGroupInvitation[] _getGroupsInvitation(int retrieveUser) {
        User res = user.retrieveUser(retrieveUser);
        return res.getGroupInvitations().toArray(new IGroupInvitation[0]);
    }

    private IGroup _getGroupInfo(int groupId) {
        return group.retrieveGroup(groupId);
    }

    private IGroupRole[] _getGroups(int sourceUser) {
        return group.getGroups(new User(sourceUser)).toArray(new IGroupRole[0]);
    }

    private IGroupRole[] _getGroupMembers(int groupId) {
        return group.getGroupMember(new GroupEx(groupId)).toArray(new IGroupRole[0]);

    }
}
